/*
 * VideoEncode.cpp
 *
 *  Created on: 2014-4-9
 *      Author: root
 */
#include "VideoEncode.hh"

VideoEncode* VideoEncode::createNew(int Width ,int Height)
{
	if((0 < Width) && (0 < Height))
	{
		return new VideoEncode(Width, Height);
	}
	else
	{
		return NULL;
	}
}

VideoEncode::VideoEncode(int Width ,int Height)
{
	m_usWidth = Width;
	m_usHeight = Height;
}
VideoEncode::~VideoEncode(void)
{

}

//初始化编码器
void VideoEncode::init_encoder(int Fps)
{
	encode_op.param = (x264_param_t *) malloc(sizeof(x264_param_t));
	encode_op.picture = (x264_picture_t *) malloc(sizeof(x264_picture_t));
	x264_param_default(encode_op.param); //set default param

	if(x264_param_default_preset(encode_op.param,"veryfast","zerolatency")<0)
	{
		printf("x264_param_default_preset error!\n");
		return;
	}

	encode_op.param->i_width = m_usWidth; //set frame width
	encode_op.param->i_height = m_usHeight; //set frame height
	//encode_op.param->rc.i_lookahead = 0; //表示i帧向前缓冲区
	encode_op.param->i_fps_num = Fps; //帧率分子
	encode_op.param->i_fps_den = 1; //帧率分母

	//--------------------------
	//add  set param
	///*
	encode_op.param->i_keyint_max = Fps*2;
	encode_op.param->b_intra_refresh = 1;
	encode_op.param->i_threads = X264_SYNC_LOOKAHEAD_AUTO;
	encode_op.param->b_annexb = 1;
	encode_op.param->rc.f_rf_constant = 25;
	encode_op.param->rc.f_rf_constant_max = 45;
	encode_op.param->i_level_idc=30;
	encode_op.param->rc.i_rc_method = X264_RC_CQP;//参数i_rc_method表示码率控制，CQP(恒定质量)，CRF(恒定码率)，ABR(平均码率)
//	encode_op.param->i_vbv_max_bitrate=(int)((m_bitRate*1.2)/1000) ;
	encode_op.param->b_repeat_headers = 1;  // 重复SPS/PPS 放到关键帧前面

//	encode_op.param->rc.i_bitrate=900;
//	encode_op.param->rc.i_qp_min=2;
//	encode_op.param->rc.i_qp_max=31;
//	encode_op.param->rc.f_qcompress=0.5f;
//	encode_op.param->rc.i_qp_constant=0;
//	encode_op.param->rc.f_aq_strength = 0.3f;
//	encode_op.param->i_log_level = X264_LOG_NONE;

	//* 流参数
	encode_op.param->i_bframe  = 5;
	encode_op.param->b_open_gop  = 0;
	encode_op.param->i_bframe_pyramid = 0;
	encode_op.param->i_bframe_adaptive = X264_B_ADAPT_TRELLIS;
	encode_op.param->i_timebase_den = encode_op.param->i_fps_num;
	encode_op.param->i_timebase_num = encode_op.param->i_fps_den;
	//*/
	//------------------------------

	x264_param_apply_profile(encode_op.param, x264_profile_names[0]); //使用baseline

	if ((encode_op.x264_encoder = x264_encoder_open(encode_op.param)) == 0) {
		return;
	}
	/* Create a new pic */
	x264_picture_alloc(encode_op.picture, X264_CSP_I420, encode_op.param->i_width,	encode_op.param->i_height);
	encode_op.picture->img.i_csp = X264_CSP_I420;
	encode_op.picture->img.i_plane = 3;
}

//编码一帧图像
int VideoEncode::encode_frame(int frame_type, uint8_t *picture_in,uint8_t *picture_out)
{

	x264_picture_t pic_out;
	int nNal = -1;
	int i = 0;
	int result = 0;
	uint8_t *p_out = picture_out;
	if(picture_in)
	{
		encode_op.picture->img.i_csp = X264_CSP_I420;
		encode_op.picture->img.i_plane = 3;
		//encode_op.picture->i_type=X264_TYPE_AUTO;
		encode_op.picture->img.plane[0] = picture_in;
		encode_op.picture->img.plane[1] = picture_in + m_usWidth*m_usHeight;
		encode_op.picture->img.plane[2] = picture_in + m_usWidth*m_usHeight + m_usWidth * m_usHeight/4;

		switch (frame_type)
		{
		case 0:
			encode_op.picture->i_type = X264_TYPE_P;
			break;
		case 1:
			encode_op.picture->i_type = X264_TYPE_IDR;
			break;
		case 2:
			encode_op.picture->i_type = X264_TYPE_I;
			break;
		default:
			encode_op.picture->i_type = X264_TYPE_AUTO;
			break;
		}

		if (x264_encoder_encode(encode_op.x264_encoder, &(encode_op.nal), &nNal, encode_op.picture,&pic_out) < 0)
		{
			return -1;
		}

		for (i = 0; i < nNal; i++)
		{
			memcpy(p_out, encode_op.nal[i].p_payload, encode_op.nal[i].i_payload);
			p_out += encode_op.nal[i].i_payload;
			result += encode_op.nal[i].i_payload;
		}

	return result;
	}

	else
	{
		return -1;
	}
}
//释放编码器
void VideoEncode::release_encoder(void)
{
	if (encode_op.picture)
	{
		//x264_picture_clean(encode_op.picture);
		free(encode_op.picture);
		encode_op.picture = NULL;
	}
	if (encode_op.param)
	{
		free(encode_op.param);
		encode_op.param = NULL;
	}
	if (encode_op.x264_encoder)
	{
		x264_encoder_close(encode_op.x264_encoder);
	}
}
/*
x264_t *x264_encoder;
unsigned short 	m_usWidth;
unsigned short 	m_usHeight;
//*/
